/*
 * CgInitializer.c
 *
 *  Created on: 2012/06/11
 *      Author: guanxiaoying
 */
#include "../coredef.h"
#include "../cc/cc.h"
#include "cg.h"

static VOID cg_AssignBlockToVariable( AST astVari, AST astInit, CG_RESULT *result );
static BOOL cg_InitIsConstString( AST astExp ){
	if( stExpressionAccess.opKind.get( astExp ) == EXPR_STRING ){
		return TRUE;
	}
	return FALSE;
}
static BOOL cg_InitIsCharArray( AST astLinkType ){
	AST astEleType;
	if( TYPEKIND_ARRAY == stLinkTypeInfoAccess.typeKind.get( astLinkType )){
		astEleType = stLinkTypeInfoAccess.elementType.get( astLinkType );
		if( stLinkTypeInfoAccess.size.get( astEleType ) == 1
			&& ( TYPEKIND_BASIC == stLinkTypeInfoAccess.typeKind.get( astEleType )) ){
			return TRUE;
		}
	}
	return FALSE;
}
static VOID cg_recordInitExp( AST astVari, AST astInit, CG_RESULT *result  ){
	AST astExp;
	AST astCmdList;
	AST astOperand;
	CG_RESULT result_child = {0,0};

	astExp = stExpressionListAccess.expression.get( astInit );
	result_child = CG_Expression( astExp, TRUE );
	if( result_child.astBegin > 0 ){
		*result = CG_MergeResult( *result, result_child );
		stVariableInfoAccess.initialCmdBegin.set( astVari, result_child.astBegin );
		stVariableInfoAccess.initialCmdEnd.set( astVari, result_child.astEnd );
		astCmdList = CG_NewCmdListByKind( ASM_CMD_ASSIGN, astExp );
		astOperand = CG_NewVariableOperand( astVari );
		stCmdListAccess.leftOperand.set( astCmdList, astOperand );
		astOperand = CG_NewResultOperand( result_child.astEnd );
		stCmdListAccess.rightOperand.set( astCmdList, astOperand );
		*result = CG_MergeCmdList( *result, astCmdList );
	}
	result_child = CG_ExpPullPostIncDec(TRUE);
	if( result_child.astBegin > 0 ){
		*result = CG_MergeResult( *result, result_child );
	}
}
static AST cg_AssignExpToVariable( AST astVari, AST astInit, CG_RESULT *result ){
	AST astExp;
	AST astLinkType;

	astExp = stExpressionListAccess.expression.get( astInit );
	astLinkType = stVariableInfoAccess.type.get( astVari );
	if( cg_InitIsCharArray( astLinkType ) && cg_InitIsConstString( astExp ) ){
		cg_recordInitExp( astVari, astExp, result );
	}else{
		if( EXPR_COMPOUNDLITERALS == stExpressionAccess.opKind.get( astExp ) ){
			astExp = stExpressionAccess.rightChild.get( astExp );
			astInit = stExpressionAccess.result_exprlist.get( astExp );
			cg_AssignBlockToVariable( astVari, astInit, result );
		}else{
			cg_recordInitExp( astVari, astInit, result );
		}
	}
	return astVari;
}
static AST cg_getMemByName( AST astVari, PSZ name ){
	PSZ pszName;
	AST astChildObj;
	if( str_length( name ) == 0 ){
		return 0;
	}
	astChildObj = stVariableInfoAccess.child.get( astVari );
	while( astChildObj > 0  ){
		pszName = stVariableInfoAccess.name.get( astChildObj );
		if( strcmp( pszName, name ) == 0 ){
			return astChildObj;
		}
		astChildObj = stVariableInfoAccess.next.get( astChildObj );
	}
	return 0;
}
static AST  cg_getVariByDesignation( AST astVari, AST astDesignation  ){
	U2 dekind;
	PSZ name;
	AST astType;
	AST astTargetObj = 0;

	while( astDesignation ){
		astType = stVariableInfoAccess.type.get( astVari );
		dekind = stInitDesignationAccess.kind.get( astDesignation ) ;
		if( dekind == DESIGNATION_MEMBER ){
			name = stSymbolInfoAccess.name.get(stInitDesignationAccess.identifier.get( astDesignation ) ) ;
			if( stLinkTypeInfoAccess.typeKind.get( astType ) == TYPEKIND_STRUCT ){
				astTargetObj = cg_getMemByName( astVari, name );
			}else if( stLinkTypeInfoAccess.typeKind.get( astType ) == TYPEKIND_UNION ){
				astTargetObj = cg_getMemByName( astVari, name );
			}else{
				astTargetObj = 0;
			}
		}else if( dekind == DESIGNATION_ARRAY ){
			if( stLinkTypeInfoAccess.typeKind.get( astType ) == TYPEKIND_ARRAY ){
				AST astExp = stInitDesignationAccess.const_expression.get( astDesignation );
				AST astValue = stExpressionAccess.constValue.get( astExp );
				VARVALUE v1;
				if( astValue == 0 ){
					astTargetObj = 0;
				}else{
					v1 = CcValueGetInteger( astValue );
					if( v1.sign < 0 ){
						astTargetObj = 0;
					}else{
						astTargetObj = stVariableInfoAccess.child.get( astVari );
						while( v1.u8Remainder > 0 ){
							astTargetObj = stVariableInfoAccess.next.get( astVari );
							v1.u8Remainder--;
						}
					}
				}
			}else{
				astTargetObj = 0;
			}
		}
		if( astTargetObj == 0 ){
			break;
		}
		astVari = astTargetObj;
		astDesignation = stInitDesignationAccess.child.get( astDesignation ) ;
	}
	return astTargetObj;
}
static VOID cg_AssignBlockToVariable( AST astVari, AST astInit, CG_RESULT *result ){
	AST astSubVari;
	AST astCurrVari;
	AST astParent;
	U2  paramKind;
	BOOL bFixed;
	AST astDesignation;

	astSubVari = stVariableInfoAccess.child.get( astVari );
	if( astSubVari == 0 ){
		/* block to single object */
		astInit = stExpressionListAccess.expressionList.get( astInit );
		paramKind = stExpressionListAccess.parameterKind.get( astInit );
		while( paramKind == KIND_INITIALEXPLIST ){
			astInit = stExpressionListAccess.expressionList.get( astInit );
			paramKind = stExpressionListAccess.parameterKind.get( astInit );
		}
		if( paramKind == KIND_EXPRESSIONINFO ){
			cg_AssignExpToVariable( astVari, astInit, result );
		}
		return;
	}
	astInit = stExpressionListAccess.expressionList.get( astInit );
	astCurrVari = 0;
	while( astInit ){
		/*  process per initializer */
		bFixed = FALSE;
		astDesignation = stExpressionListAccess.designation.get( astInit );
		if( astDesignation > 0 ){
			astSubVari = cg_getVariByDesignation( astVari, astDesignation );
			if( astSubVari > 0 ){
				astCurrVari = astSubVari;
				astParent = stVariableInfoAccess.parent.get( astCurrVari );
			}
			bFixed = TRUE;
		}else{
			if( astCurrVari == 0 ){
				/* first one */
				astCurrVari = stVariableInfoAccess.child.get( astVari );
				astParent = astVari;
			}else{
				/* from second one */
				astCurrVari = stVariableInfoAccess.next.get( astCurrVari );
			}
			/* go to the parent level when all objects are assigned in this level */
			while( astCurrVari == 0 ){
				astCurrVari = astParent ;
				astParent= stVariableInfoAccess.parent.get( astCurrVari );
				if( astCurrVari == astVari || astCurrVari == 0 ){
					astCurrVari = 0;
					break;
				}
				astCurrVari = stVariableInfoAccess.next.get( astCurrVari );
			}
		}
		if( astCurrVari == 0 ){
			break;
		}
		paramKind = stExpressionListAccess.parameterKind.get( astInit );
		if( paramKind == KIND_EXPRESSIONINFO ){
			if( bFixed ){
				cg_AssignExpToVariable( astCurrVari, astInit, result );
			}else{
				astCurrVari = cg_AssignExpToVariable( astCurrVari, astInit, result );
				astParent= stVariableInfoAccess.parent.get( astCurrVari );
			}
		}else{
			cg_AssignBlockToVariable( astCurrVari, astInit, result );
		}
		astInit = stExpressionListAccess.next.get( astInit );
	}
}
CG_RESULT CG_AssignInitializerToVariable( AST astVari, AST astInitializer, BOOL bAssign ){
	U2  paramKind = stExpressionListAccess.parameterKind.get( astInitializer );
	CG_RESULT result={0,0};

	if( paramKind == KIND_EXPRESSIONINFO  ){
		cg_AssignExpToVariable( astVari, astInitializer, &result );
	}else{
		cg_AssignBlockToVariable( astVari, astInitializer,  &result );
	}
	return result;
}

